package com.lanzuo.yxd.scanner.conveyor;

import com.ghgande.j2mod.modbus.facade.ModbusTCPMaster;
import com.ghgande.j2mod.modbus.procimg.InputRegister;
import com.ghgande.j2mod.modbus.procimg.Register;
import com.ghgande.j2mod.modbus.procimg.SimpleInputRegister;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

public class ModbusMaster {
    static final Integer UNIT_ID = 1;
    private String ip;
    private Integer port;

    public ModbusMaster(String ip, Integer port) {
        this.ip = ip;
        this.port = port;
    }

    private int[] stringToRegisters(String text, String charset) throws Exception {
        byte[] bytes = text.getBytes(charset); // 如 "GBK" 或 "UTF-8"

        // 补齐偶数长度（Modbus 寄存器是 16 位 = 2 字节）
        if (bytes.length % 2 != 0) {
            byte[] newBytes = new byte[bytes.length + 1];
            System.arraycopy(bytes, 0, newBytes, 0, bytes.length);
            newBytes[bytes.length] = 0; // 补 \0
            bytes = newBytes;
        }

        int[] registers = new int[bytes.length / 2];
        ByteBuffer buffer = ByteBuffer.wrap(bytes);
        buffer.order(ByteOrder.BIG_ENDIAN); // 或 LITTLE_ENDIAN，看PLC要求

        for (int i = 0; i < registers.length; i++) {
            registers[i] = buffer.getShort() & 0xFFFF; // 转为无符号 short
        }
        return registers;
    }

    private String registersToString(int[] registers, String charset) throws Exception {
        ByteBuffer buffer = ByteBuffer.allocate(registers.length * 2);
        buffer.order(ByteOrder.BIG_ENDIAN); // 必须和写入一致！

        for (int reg : registers) {
            buffer.putShort((short) reg);
        }

        byte[] bytes = buffer.array();
        // 去除尾部的 \0（可选）
        int len = bytes.length;
        while (len > 0 && bytes[len - 1] == 0) len--;

        return new String(bytes, 0, len, charset);
    }


    /**
     * 寄存器写数据
     *
     * @param address 寄存器地址
     * @param text    新值
     * @return 写入的值返回，异常则返回null
     */
    public Integer writeString(Integer address, String text) throws Exception {
        ModbusTCPMaster master = null;
        try {
            // 创建 TCP Master，连接到从站 Modbus.DEFAULT_PORT 默认端口 502
            master = new ModbusTCPMaster(ip, port);
            master.connect();
            int[] msgs = stringToRegisters(text, "GBK");
            Register[] register = new Register[msgs.length];
            for (int i = 0; i < register.length; i++) {
                register[i] = new SimpleInputRegister();
                register[i].setValue(msgs[i]);
            }

            return master.writeMultipleRegisters(UNIT_ID, address, register);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (master != null) {
                master.disconnect();
            }
        }

        return null;
    }

    /**
     * 寄存器写数据
     *
     * @param address 寄存器地址
     * @param value   新值
     * @return 写入的值返回，异常则返回null
     */
    public Integer writeSignal(Integer address, Integer value) {
        ModbusTCPMaster master = null;
        try {
            // 创建 TCP Master，连接到从站 Modbus.DEFAULT_PORT 默认端口 502
            master = new ModbusTCPMaster(ip, port);
            master.connect();

            Register register = new SimpleInputRegister();
            register.setValue(value);
            return master.writeSingleRegister(UNIT_ID, address, register);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (master != null) {
                master.disconnect();
            }
        }

        return null;
    }

    /**
     * 寄存器读值
     *
     * @param address 寄存器地址
     * @return value or null(读取异常)
     */
    public Integer readSignal(Integer address) {
        ModbusTCPMaster master = null;
        try {
            // 创建 TCP Master，连接到从站 Modbus.DEFAULT_PORT 默认端口 502
            master = new ModbusTCPMaster(ip, port);
            master.connect();

            InputRegister[] registers = master.readMultipleRegisters(UNIT_ID, address, 1);

            if (registers.length > 0) {
                return registers[0].getValue();
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (master != null) {
                master.disconnect();
            }
        }

        return null;
    }
}
